← PersonaDLE

PersonaDLE

Documentation v2.0 — Mai 2026

Nouveautés, modes de jeu, social, profil & notes techniques

v2.0 Documentation — May 2026

What's new, game modes, social features, profile & technical notes

6 modes 449 tests 947 i18n keys 23 DB tables 60 badges
PersonaDLE v2.0

🎨 Nouveau logo

🎨 New Logo

Avant

Before

Ancien logo PersonaDLE

Après

After

Nouveau logo PersonaDLE

Nouveautés v2.0

What's New in v2.0

La v2.0 passe d'un jeu localStorage uniquement à une plateforme complète : backend PHP/MariaDB, comptes utilisateurs, social, et infrastructure CI/CD.

v2.0 transforms PersonaDLE from a localStorage-only game into a full platform: PHP/MariaDB backend, user accounts, social features, and CI/CD infrastructure.

🔐
Accounts & Auth Comptes & Auth Register, login, bcrypt, PHP sessions, cloud sync Inscription, connexion, bcrypt, sessions PHP, sync cloud
👥
Social System Système Social Friends, Social Link ranks 1-10, daily challenges Amis, rangs Social Link 1-10, défis quotidiens
🌍
5 Languages 5 Langues EN · FR · ES · DE · IT — 940+ keys, auto-detect EN · FR · ES · DE · IT — 940+ clés, détection auto
🏅
Badges, Titles & Wallpapers Badges, Titres & Fonds 60 badges, 11 titles (Rare/Epic/Legendary), 7 wallpapers 60 badges, 11 titres (Rare/Épique/Légendaire), 7 fonds
🏆
Leaderboard Global & Friends scope, 5 metrics, cron-cached Portée Global & Amis, 5 métriques, cache cron
🎵
130+ Tracks in Music Mode 130+ Pistes en Mode Musique Custom P5-style player, per-series color themes Lecteur custom style P5, thèmes couleur par série
🛡️
Security & GDPR Sécurité & RGPD CSRF protection, rate limiting, admin audit trail, soft-delete J+30 Protection CSRF, rate limiting, audit trail admin, soft-delete J+30
Accessible Modals Modales Accessibles Keyboard focus trap & Escape on avatar, music, colors, titles Focus clavier cantonné & Escape sur avatar, musique, couleurs, titres
⚙️
CI/CD & Docker GitHub Actions, git hooks, rsync deploy to Hostinger GitHub Actions, git hooks, déploiement rsync Hostinger
New Characters & Music Nouveaux Personnages & Musiques P5S antagonists, P5X Summer event chars, 12 new tracks Antagonistes P5S, persos événement P5X Summer, 12 nouvelles pistes
💬
Discord Collab — Le Grimoire du Cœur Collab Discord — Le Grimoire du Cœur Discord button now opens both communities: PersonaDLE (international) and our French partner server Le bouton Discord ouvre désormais les deux communautés : PersonaDLE (international) et notre serveur partenaire francophone
PersonaDLE v2.0 banner 5 languages support EN · FR · ES · DE · IT — 940+ keysEN · FR · ES · DE · IT — 940+ clés

🐛 Corrections récentes

🐛 Recent Fixes

🖼️
Silhouette & All-Out Attack: no more image drag-and-reveal Silhouette & All-Out Attack : plus de triche par glisser-déposer You could click-drag the picture out of its frame to see the answer early. Fixed on both modes. On pouvait cliquer-glisser l'image hors de son cadre pour voir la réponse en avance. Corrigé sur les deux modes.
🃏
Classic: Give Up no longer counts as a win Classique : Abandonner ne compte plus comme une victoire Giving up in Classic mode was silently logged as a win, inflating stats and unlocking win-only badges. Abandonner en mode Classique était silencieusement compté comme une victoire, faussant les stats et débloquant des badges réservés aux victoires.
🟩
Classic: victory box now properly styled Classique : boîte de victoire enfin stylée The green victory panel was missing its background and border in Classic mode. Fixed. Le panneau vert de victoire n'affichait plus son fond ni sa bordure en mode Classique. Corrigé.

Modes de jeu

Game Modes

PersonaDLE propose 6 modes quotidiens, chacun avec un défi différent basé sur les personnages de la saga Persona (P1 → P5X).

PersonaDLE offers 6 daily modes, each with a different challenge based on Persona series characters (P1 → P5X).

🎭

Classic

Classique

Devinez le personnage du jour en comparant ses attributs : nom, genre, âge, persona, arcane, opus. Chaque tentative révèle des indices par couleur.

Guess the daily character by comparing attributes: name, gender, age, persona, arcana, opus. Each attempt reveals color-coded hints.

8 attempts
😀

Emoji

Identifiez le personnage à partir d'une série d'emojis qui représentent sa personnalité, ses attributs ou son histoire.

Identify the character from a series of emojis representing their personality, attributes, or story.

8 attempts
👤

Silhouette

Reconnaissez le personnage depuis sa silhouette, qui se révèle progressivement à chaque tentative manquée.

Recognize the character from their silhouette, which gradually reveals itself with each missed attempt.

6 attempts
💥

All-Out Attack

Identifiez le personnage depuis son animation d'All-Out Attack floue, qui devient plus nette à chaque tentative.

Identify the character from their blurred All-Out Attack animation, which sharpens with each attempt.

5 attempts
🃏

Personae

Personae

Devinez le personnage en voyant uniquement ses Personas. La difficulté augmente progressivement.

Guess the character by seeing only their Personas. Difficulty increases progressively.

6 attempts
🎵

Music

Musique

Identifiez la chanson jouée dans le lecteur audio. 130+ pistes couvrant P1 → P5X, filtrables par opus.

Identify the song playing in the audio player. 130+ tracks covering P1 → P5X, filterable by opus.

130+ tracks
Filtres opus Sub-filters per game (P3, P4, P5…)Sous-filtres par jeu (P3, P4, P5…)

Nouveau contenu

New Content

New Characters

Nouveaux Personnages

Antagonistes (P3, P4, P5) — Les boss finaux sont maintenant jouables dans les modes compatibles :

Antagonists (P3, P4, P5) — Final bosses are now playable in compatible modes:

Nyx
Nyx P3 / P3FES / P3P / P3R — Death
Classic · Silhouette Classique · Silhouette
Ameno-sagiri
Ameno-sagiri P4 / P4G
Classic Classique
Yaldabaoth
Yaldabaoth P5 / P5R / P5S
Classic · Silhouette Classique · Silhouette

Persona 5 Strikers — 6 nouveaux personnages :

Persona 5 Strikers — 6 new characters:

Portrait Portrait Character Personnage Category Catégorie Shadow / Persona
Akane Hasegawa Akane Hasegawa SecondarySecondaire Shadow Akane
Kuon Ichinose Kuon Ichinose SecondarySecondaire
Alice Hiiragi Alice Hiiragi Antagonist — Jail RulerAntagoniste — Jail Ruler Mad Rabbit Alice
Ango Natsume Ango Natsume Antagonist — Jail RulerAntagoniste — Jail Ruler Nightmare Dragon Ango
Mariko Hyodo Mariko Hyodo Antagonist — Jail RulerAntagoniste — Jail Ruler Snow Empress Mariko
Akira Konoe Akira Konoe Main Antagonist (BAAL)Antagoniste principal (BAAL) Akira the Hero

Persona 5: The Phantom X — New Phantom Idols: playable across Classic, Silhouette and Personae.

Persona 5: The Phantom X — Nouveaux Phantom Idols : jouables en Classique, Silhouette et Personae.

Aran Hirano
Aran Hirano (Anri) P5X — Gentileschi
Classic · Silhouette · Personae Classique · Silhouette · Personae
Gentileschi Gentileschi
Narumi Nashimoto
Narumi Nashimoto (Pinky) P5X — Asterope
Classic · Silhouette · Personae Classique · Silhouette · Personae
Asterope Asterope
Kumi Katayama
Kumi Katayama (Blitz) P5X — Kiskil-lilla
Classic · Silhouette · Personae Classique · Silhouette · Personae
Kiskil-lilla Kiskil-lilla

New Characters — All-Out Attack Mode

Nouveaux Personnages — Mode All-Out Attack

Joker Starlight joins the All-Out Attack roster — a Dancing in Starlight variant with a unique animated finish screen.

Joker Starlight rejoint le mode All-Out Attack — une variante Dancing in Starlight avec un écran de fin animé unique.

Joker Starlight portrait
Joker Starlight All-Out Attack
Joker Starlight Battle
P5X

Joker Starlight

Ren Amamiya — Persona 5 X

Mona Starlight portrait
Mona Starlight All-Out Attack
Mona Starlight Battle
P5X

Mona Starlight

Morgana — Persona 5 X

☀️ Summer 2026 — P5X Summer Event

☀️ Été 2026 — Événement Summer P5X

Three limited Summer event characters, each with a distinct beach-themed All-Out Attack animation.

Trois personnages limités de l'événement Summer, chacun avec une animation All-Out Attack sur le thème de la plage.

Wonder Summer portrait
Wonder Summer All-Out Attack
Wonder Summer Battle
P5X

Wonder Summer

Nagisa Kamishiro — Persona 5 X

Closer Summer portrait
Closer Summer All-Out Attack
Closer Summer Battle
P5X

Closer Summer

Motoha Arai — Persona 5 X

Moko Summer portrait
Moko Summer All-Out Attack
Moko Summer Battle
P5X

Moko Summer

Tomoko Noge — Persona 5 X

Marian Summer portrait
Marian Summer All-Out Attack
Marian Summer Battle
P5X

Marian Summer

Minami Miyashita — Persona 5 X

Puppet Summer portrait
Puppet Summer All-Out Attack
Puppet Summer Battle
P5X

Puppet Summer

Miyu Sahara — Persona 5 X

🌈 Radiance — P5X Event

🌈 Radiance — Événement P5X

Closer Radiance portrait
Closer Radiance All-Out Attack
Closer Radiance Battle
P5X

Closer Radiance

Motoha Arai — Persona 5 X

🎭 New Phantom Idols — P5X

🎭 Nouveaux Phantom Idols — P5X

Anri portrait
Anri All-Out Attack
Anri Battle
P5X

Anri

Aran Hirano — Persona 5 X

Pinky portrait
Pinky All-Out Attack
Pinky Battle
P5X

Pinky

Narumi Nashimoto — Persona 5 X

Blitz portrait
Blitz All-Out Attack
Blitz Battle
P5X

Blitz

Kumi Katayama — Persona 5 X

🎤 Hatsune Miku — P5X Collaboration

🎤 Hatsune Miku — Collaboration P5X

The virtual diva crosses over into Persona 5 X! Hatsune Miku joins the All-Out Attack roster with a vivid cyan-pink-red finish — her real name behind the alias "Miku", just like Joker is Ren Amamiya.

La diva virtuelle débarque dans Persona 5 X ! Hatsune Miku rejoint le mode All-Out Attack avec un final cyan-rose-rouge éclatant — son vrai nom derrière l'alias « Miku », comme Joker est Ren Amamiya.

Hatsune Miku portrait
Hatsune Miku All-Out Attack
Hatsune Miku Battle
P5X

Miku

Hatsune Miku — Persona 5 X

Music mode

New Music Tracks

Nouvelles Pistes Musicales

P3PP3P
Danger Zone(instrumental)
TimeMayumi Fujita
P3RP3R
Want to Be Close -Reload-Azumi Takahashi
P4AUP4AU
A Fool or Clown?(instrumental)
Best FriendsYumi Kawamura
Break Out OfShihoko Hirata, Lotus Juice
P4GP4G
I'll Face Myself -Battle-(instrumental)
P5RP5R
Throw Away Your MaskLyn Inaizumi
P5SP5S
Axe to GrindLyn Inaizumi
Counter StrikeLyn Inaizumi
P5TP5T
Got Your TailLyn Inaizumi
Revolution is a BladeLyn Inaizumi
Truth or DareLyn Inaizumi

Couvertures disponibles pour 20 opus (P1 → P5X, PQ/PQ2, Velvet, Zutomayo). P4AU et P5T ajoutés en tant que nouveaux filtres dans le panneau de sélection.

Covers available for 20 opus (P1 → P5X, PQ/PQ2, Velvet, Zutomayo). P4AU and P5T added as new filter options in the selection panel.


Fonctionnalités Sociales

Social Features

Social features

Friends

Amis

Social Link

Inspiré des jeux Persona, chaque relation entre amis progresse en rang (1 → 10) via des interactions mutuelles. Les actions mutuelles donnent 2× l'XP. Anti-spam : une action par type par jour par lien.

Inspired by the Persona games, each friendship progresses in rank (1 → 10) through mutual interactions. Mutual actions grant 2× XP. Anti-spam: one action per type per day per link.

Rang / Rank Nom / Name XP
1Stranger0
2Acquaintance100
3Companion250
4Ally450
5Confidant700
6Trusted Ally1 000
7True Ally1 350
8Bond1 750
9Unbreakable Bond2 200
10True Confidant ✦2 700

Au rang 10 (True Confidant), un effet visuel spécial s'active : halo doré pulsant autour de l'avatar, icône ✦ et label animé.

At rank 10 (True Confidant), a special visual effect activates: pulsing gold halo around the avatar, ✦ icon, and animated label.

Daily Challenges

Défis Quotidiens

Leaderboard

Profil & Compte

Profile & Account

Profile Page

Page de Profil

Badges

Badges

60 badges organisés en 5 catégories : Achievements, Events, Secrets, Social, Streak. Les conditions sont vérifiées côté serveur. Les badges secrets affichent "???" comme condition tant qu'ils ne sont pas débloqués.

60 badges organized into 5 categories: Achievements, Events, Secrets, Social, Streak. Conditions are verified server-side. Secret badges display "???" as their condition until unlocked.

Titres

Titles

Titres

11 titres affichés sous le pseudo. Un seul titre équipé à la fois. Traduits EN/FR/ES/DE/IT.

11 titles displayed below the username. Only one title equipped at a time. Translated in EN/FR/ES/DE/IT.

★ ★
Rare
I Am Not Afraid
I Am Not Afraid
Persona 3
Win 50 games in Classic Mode
★ ★ ★
Epic
Reach Out to the Truth
Reach Out to the Truth
Persona 4
Complete 100 games across all modes
✦ ✦ ✦ ✦
Legendary
Memento Mori
Memento Mori
Persona 3 Reload
Achieve a 30-day streak

Wallpapers & Event Codes

Fonds d'écran & Codes Événement


Notes Techniques

Technical Notes

Cette section est destinée aux développeurs. Elle couvre le stack, l'API, la base de données, la sécurité et le CI/CD.

This section is for developers. It covers the stack, API, database, security, and CI/CD.

PHP Backend integration

Stack

Stack

LayerCoucheTechnologyTechnologie
FrontendFrontendVanilla JS ES6+, HTML5, CSS3 — zero framework
BackendBackendPHP 8.3 + PDO (prepared statements)
DatabaseBase de donnéesMySQL 8.0 (local) · MariaDB 10.6+ (Hostinger)
AuthAuthbcrypt + PHP httpOnly sessions (no JWT)
TestsTestsVitest + jsdom — 449 tests (npm test)
HostingHébergementHostinger — rsync deploy via GitHub Actions
JavaScript corrections CSS style adaptation

JavaScript Architecture

Architecture JavaScript

Modules clés dans js/ :

Key modules in js/:

ModuleRoleRôle
gameCore.jsShared utilities: date (DST-safe Paris), confetti, sessions, filtersUtilitaires partagés : date (DST Paris), confetti, sessions, filtres
api.jsREST client — exposed as window._personadleApi to avoid circular importsClient REST — exposé via window._personadleApi pour éviter les imports circulaires
auth.jsLogin/register UI, initAuth(), localStorage → cloud migrationUI login/register, initAuth(), migration localStorage → cloud
i18n.jsTranslation engine: t(key), initLang(), applyToDOM()Moteur de traduction : t(key), initLang(), applyToDOM()
cloud-sync.jsBackend is source of truth — pullProfileFromCloud() overwrites localStorageBackend = source de vérité — pullProfileFromCloud() écrase le localStorage
social-link.jsXP gauges, rank-up animation, True Confidant effectJauges XP, animation rang-up, effet True Confidant
i18n: critical pitfall i18n : piège critique

t(key) returns the raw key (truthy string) when missing — ?? never triggers. Always use:

t(key) retourne la clé brute (string truthy) quand elle est absente — ?? ne se déclenche jamais. Utiliser :

const r = window.i18n?.t?.(key);
return (r != null && r !== key) ? r : fallback;

Database Schema — 23 Tables

Schéma BDD — 23 Tables

Fichier : sql/bdd_mysql.sql. Schéma compatible MySQL 8.0 (local) et MariaDB 10.6+ (Hostinger).

File: sql/bdd_mysql.sql. Schema compatible with MySQL 8.0 (local) and MariaDB 10.6+ (Hostinger).

View all 23 tablesVoir les 23 tables
TableDescriptionDescription
usersAccount (email, pseudo, hash, friend_code, is_banned)Compte (email, pseudo, hash, friend_code, is_banned)
profilesAvatar, wallpaper, equipped badge/title/songAvatar, fond, badge/titre/chanson équipés
user_statsStats per mode (wins, streak, perfect, time_ms)Stats par mode (wins, streak, perfect, time_ms)
game_sessionsGame history (anti-duplicate per user+mode+date)Historique des parties (anti-duplon user+mode+date)
badges / badges_unlocked60-badge catalog + per-user unlocksCatalogue 60 badges + déblocages par utilisateur
wallpapers / user_wallpapers7 wallpapers + per-user unlocks7 fonds + déblocages par utilisateur
titles / user_titles11 translated titles + per-user unlocks11 titres traduits + déblocages par utilisateur
event_codes / event_codes_redeemedEvent codes (active, dates, badge reward)Codes événement (actif, dates, récompense badge)
friendshipsFriend requests (pending / accepted / blocked)Demandes d'amis (pending / accepted / blocked)
social_links / social_link_interactionsSocial Link rank + XP + interaction logRang + XP Social Link + log des interactions
social_link_ranksXP thresholds for ranks 1-10Seuils XP des rangs 1-10
social_link_rankup_notifsRank-up notifications for both playersNotifications de passage de rang pour les deux joueurs
messagesMessages and challenges between friendsMessages et défis entre amis
leaderboard_cacheCached rankings (recalculated by cron)Cache des classements (recalculé par cron)
rate_limitsAnti-abuse counters (login, register, reset)Compteurs anti-abus (login, register, reset)
error_logApplication error log (admin panel)Journal des erreurs applicatives (panel admin)
admin_audit_logLog of every admin action (ban, grant badge, etc.)Log de chaque action admin (ban, don de badge, etc.)
deletion_requestsGDPR — soft-delete log, hard delete after 30 daysRGPD — log soft-delete, hard delete J+30

API Endpoints

Endpoints API

Full endpoint listListe complète des endpoints
EndpointDescriptionDescription
POST /api/auth/registerCreate account (users + profiles + stats × 6 in one transaction)Créer un compte (users + profiles + stats × 6 en transaction)
POST /api/auth/loginLogin — dummy hash if email not found (anti-enumeration)Connexion — hash dummy si email inexistant (anti-énumération)
GET /api/auth/meReturns {user: null} if no session (not an error)Retourne {user: null} si pas de session (pas une erreur)
POST /api/sessionsSave game session (anti-duplicate, atomic streak calc)Sauvegarder session de jeu (anti-duplon, calcul streak atomique)
GET/PATCH/DELETE /api/user/:idUser profile — ownership checks, explicit field whitelistProfil utilisateur — ownership checks, whitelist explicite des champs
POST /api/user/migrateIdempotent localStorage → DB migration (INSERT IGNORE)Migration idempotente localStorage → BDD (INSERT IGNORE)
GET /api/leaderboardRankings with mode/period/metric/scope filtersClassements avec filtres mode/période/métrique/scope
GET|POST /api/friendsFriend list, add, respond, removeListe amis, ajouter, répondre, supprimer
GET|POST /api/messagesMessages and challenges CRUDCRUD messages et défis
POST /api/social-links/:id/interactGrant XP with mutual detection (×2)Accorder XP avec détection mutualité (×2)
GET /api/badges, /api/wallpapers, /api/titlesCatalogs + condition-verified unlocksCatalogues + déblocages vérifiés par condition
GET|POST /api/admin/…Admin — user management, event codes, moderationAdmin — gestion utilisateurs, codes événement, modération
GET /api/cron/leaderboard.phpRecalculate 105 leaderboard entries (hourly)Recalcul 105 entrées leaderboard (toutes les heures)
GET /api/cron/hard-delete.phpGDPR hard delete J+30 (daily)Hard delete RGPD J+30 (quotidien)
Admin rights

Security

Sécurité

Severity Sévérité Issue fixed Faille corrigée
CRITICAL Unconditional badge/title/wallpaper unlock — any authenticated account could self-award any item Unlock inconditionnel badges/titres/fonds — tout compte authentifié pouvait s'auto-attribuer n'importe quel item
HIGH IDOR on challenge beaten status — challenger could farm 35 XP IDOR statut beaten — l'expéditeur d'un défi pouvait se marquer beaten et farmer 35 XP
HIGH Banned user not checked on session restore (me.php) Utilisateur banni ignoré sur restauration de session (me.php)
MEDIUM Missing input validation in api/user/index.php (avatar prefix, slug regex) Validation inputs manquante dans api/user/index.php (préfixe avatar, regex slugs)
MEDIUM challenge_mode not validated — strict allowlist of 6 valid modes added challenge_mode non validé — allowlist stricte des 6 modes valides ajoutée
LOW friend_code exposed in leaderboard for unauthenticated visitors friend_code exposé dans le leaderboard pour les visiteurs non authentifiés
LOW Session fixation — session_regenerate_id(true) added to login/register Session fixation — session_regenerate_id(true) ajouté dans login/register

Rate limiting : 5 tentatives par fenêtre de 15 min par IP sur /api/auth/login et /api/auth/register. Headers de sécurité ajoutés dans api/bootstrap.php : X-Content-Type-Options, X-Frame-Options: DENY, Referrer-Policy.

Rate limiting: 5 attempts per 15-minute window per IP on /api/auth/login and /api/auth/register. Security headers added in api/bootstrap.php: X-Content-Type-Options, X-Frame-Options: DENY, Referrer-Policy.

Git hooks Docker setup

CI/CD & Infrastructure

ComponentComposantDetailDétail
Git Hooks Git Hooks pre-commit: i18n check + tests. commit-msg: Conventional Commits. pre-push: full test + warn on main push pre-commit : i18n + tests. commit-msg : Conventional Commits. pre-push : tests complets + avertissement push main
GitHub Actions CI GitHub Actions CI On push to main/develop: npm test (449 tests) + i18n:check + PHP lint Sur push main/develop : npm test (449 tests) + i18n:check + lint PHP
GitHub Actions CD GitHub Actions CD Manual only (workflow_dispatch) — rsync to Hostinger via SSH, excludes .git, node_modules, api/config.php, .env Manuel uniquement (workflow_dispatch) — rsync vers Hostinger par SSH, exclut .git, node_modules, api/config.php, .env
Service Worker Service Worker CACHE_VERSION versioning. Network-first for lang/*.json to avoid stale translation cache Versioning CACHE_VERSION. Network-first pour lang/*.json — évite le cache de traductions périmé
Cron jobs Cron jobs Leaderboard cache (hourly) · GDPR hard delete (daily 03:00 Paris) Cache leaderboard (toutes les heures) · Hard delete RGPD (quotidien 03h00 Paris)

Known Pitfalls

Pièges Connus

Show pitfalls tableVoir le tableau des pièges
Issue Problème Fix Solution
t(key) ?? fallback never triggers t(key) ?? fallback ne se déclenche jamais t() returns raw key (truthy) when missing — use r !== key pattern t() retourne la clé (truthy) si absente — utiliser le pattern r !== key
syncPending blocked on 409 syncPending bloqué sur 409 409 = already saved — use continue, not return 409 = déjà enregistré — utiliser continue, pas return
rank reserved in MySQL 8.0 rank mot réservé MySQL 8.0 Always wrap in backticks: `rank` Toujours entourer de backticks : `rank`
PDO named param used twice in one prepare PDO param nommé répété deux fois dans un prepare Use positional ? and execute([$val, $val]) Utiliser ? positionnels et execute([$val, $val])
CORS with credentials: 'include' CORS avec credentials: 'include' Exact origin whitelist + Access-Control-Allow-Credentials: true Whitelist d'origines exactes + Access-Control-Allow-Credentials: true
Stacked autocomplete listeners on replay Listeners autocomplete empilés sur replay Use init flag (_acInitDone) — mutate array in-place instead of re-binding Flag d'init (_acInitDone) — muter le tableau en place plutôt que rebinder
window.onclick = fn overwrites previous handler window.onclick = fn écrase le handler précédent Always use window.addEventListener('click', fn) Toujours utiliser window.addEventListener('click', fn)
DST Paris not handled correctly DST Paris mal géré Intl.DateTimeFormat('fr-FR', { timeZone: 'Europe/Paris' }) Intl.DateTimeFormat('fr-FR', { timeZone: 'Europe/Paris' })
New PHP file in api/user/ or api/admin/ Nouveau fichier PHP dans api/user/ ou api/admin/ Each new .php file requires an explicit RewriteRule in .htaccess Chaque nouveau .php = nouvelle RewriteRule explicite dans .htaccess

PersonaDLE est un projet fan-made. Pour toute décision d'architecture majeure, documenter dans PersonaDLE_Update_Documentation/PersonaDLE 2.0/. PersonaDLE is a fan-made project. For any major architectural decision, document it in PersonaDLE_Update_Documentation/PersonaDLE 2.0/.